package com.xh3140.xwidget.app.chart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;

import androidx.annotation.ColorInt;
import androidx.annotation.Px;

import com.xh3140.xwidget.app.chart.scales.AxisScales;
import com.xh3140.xwidget.app.utils.PaintUtils;

/**
 * 坐标系基类
 * 实现了基本规范
 * 管理属性的配置
 * 绘制坐标系
 */
@SuppressWarnings("unused")
public class BaseCoordinatesView extends AbstractCoordinatesView {
  // 坐标系区域
  protected final RectF mMainRectF = new RectF(0f, 0f, 0f, 0f);

  // 坐标系绘制区域
  protected final RectF mDrawRectF = new RectF(0f, 0f, 0f, 0f);
  // 坐标轴和刻度画笔
  private final Paint mPaintAxis = new Paint(Paint.ANTI_ALIAS_FLAG);
  // 网格线画笔
  private final Paint mPaintGrids = new Paint(Paint.ANTI_ALIAS_FLAG);

  // 映射集合
  //private val mMappingSet: MutableSet<Mapping> = LinkedHashSet()
  // 坐标轴标签文本画笔
  private final Paint mPaintAxisLabel = new Paint(Paint.ANTI_ALIAS_FLAG);
  // 坐标轴刻度标签文本画笔
  private final TextPaint mPaintScalesLabel = new TextPaint(Paint.ANTI_ALIAS_FLAG);
  // 锚点坐标(动态)
  private float mAnchorX = Float.NaN;
  private float mAnchorY = Float.NaN;

  public BaseCoordinatesView(Context context) {
    super(context);
  }

  public BaseCoordinatesView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public BaseCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  public BaseCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  /**
   * 配置画笔属性
   *
   * @param type 画笔类型 [PaintType]
   */
  private void configPaint(PaintType type) {
    switch (type) {
      case AXIS:
        mPaintAxis.setColor(mAxisColor);
        mPaintAxis.setStrokeWidth(mAxisThickness);
        mPaintAxis.setStyle(Paint.Style.STROKE);
        break;
      case GRIDS:
        mPaintGrids.setColor(mGridsColor);
        mPaintGrids.setStrokeWidth(mGridsThickness);
        mPaintGrids.setStyle(Paint.Style.STROKE);
        break;
      case AXIS_LABEL:
        mPaintAxisLabel.setColor(mAxisLabelTextColor);
        mPaintAxisLabel.setTextSize(mAxisLabelTextSize);
        mPaintAxisLabel.setTypeface(mAxisLabelTypeface);
        break;
      case SCALE_LABEL:
        mPaintScalesLabel.setColor(mAxisScalesLabelTextColor);
        mPaintScalesLabel.setTextSize(mAxisScalesLabelTextSize);
        mPaintScalesLabel.setTypeface(mAxisScalesLabelTypeface);
        break;
    }
  }

  @Override
  protected float getCanvasX(float x) {
    return mAnchorX + (x - mAxisScalesX.getInitial()) * mGridsBasicX / mAxisScalesX.interval;
  }

  @Override
  protected float getCanvasY(float y) {
    return mAnchorY - (y - mAxisScalesY.getInitial()) * mGridsBasicY / mAxisScalesY.interval;
  }

  @Override
  protected float getCoordinatesX(float x) {
    return mAxisScalesX.getInitial() + (x - mAnchorX) * mAxisScalesX.interval / mGridsBasicX;
  }

  @Override
  protected float getCoordinatesY(float y) {
    return mAxisScalesY.getInitial() - (y - mAnchorY) * mAxisScalesY.interval / mGridsBasicY;
  }

  @Override
  protected boolean onScaleGesture(float focusX, float focusY, float factory) {
    // 焦点不在坐标系内
    if (focusX < mMainRectF.left || focusX > mMainRectF.right || focusY < mMainRectF.top || focusY > mMainRectF.bottom) {
      return false;
    }
    // 已缩至最小
    if (factory < 1f && (mGridsBasicX < 25f || mGridsBasicY < 25f)) {
      return false;
    }
    // 已放至最大
    if (factory > 1f && ((mGridsBasicX > mMainRectF.right - mMainRectF.left) && (mGridsBasicY > mMainRectF.bottom - mMainRectF.top))) {
      return false;
    }
    // 缩放操作
    mGridsBasicX *= factory;
    mGridsBasicY *= factory;
    // 根据缩放焦点调整锚点坐标
    mAnchorX = focusX + (mAnchorX - focusX) * factory;
    mAnchorY = focusY + (mAnchorY - focusY) * factory;
    invalidate();
    return true;
  }

  @Override
  protected boolean onScrollGesture(float startX, float startY, float distanceX, float distanceY) {
    // 起点不在坐标系内
    if (startX < mMainRectF.left || startX > mMainRectF.right || startY < mMainRectF.top || startY > mMainRectF.bottom) {
      return false;
    }
    // 在X轴活动范围内
    if (distanceX < 0 && getCanvasX(mAxisScalesX.start) - mGridsBasicX < mMainRectF.right) {
      mAnchorX -= distanceX;
    } else if (distanceX > 0 && getCanvasX(mAxisScalesX.getEnd()) + mGridsBasicX > mMainRectF.left) {
      mAnchorX -= distanceX;
    }
    // 在Y轴活动范围内
    if (distanceY < 0 && getCanvasY(mAxisScalesY.getEnd()) - mGridsBasicY < mMainRectF.bottom) {
      mAnchorY -= distanceY;
    } else if (distanceY > 0 && getCanvasY(mAxisScalesY.start) + mGridsBasicY > mMainRectF.top) {
      mAnchorY -= distanceY;
    }
    invalidate();
    return true;
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    // 配置画笔
    configPaint(PaintType.AXIS);
    configPaint(PaintType.GRIDS);
    configPaint(PaintType.AXIS_LABEL);
    configPaint(PaintType.SCALE_LABEL);
    // 确定X范围
    final int index = mAxisScalesY.index - 1;
    final int count = (int) Math.ceil(getHeight() / mGridsBasicY + 1);
    final int leftMaxWidth = mAxisScalesY.getMaximumWidth(mPaintScalesLabel, index, index + count);
    mMainRectF.left = getPaddingLeft() + leftMaxWidth + 30f;
    mMainRectF.right = getWidth() - getPaddingRight() - PaintUtils.getTextBoundsWidth(mPaintAxisLabel, mAxisLabelX) - 30f;
    if (Float.isNaN(mAnchorX)) {
      mAnchorX = mMainRectF.left + 0.5f * mGridsBasicX;
    }
    // 确定Y范围
    mMainRectF.top = getPaddingTop() + PaintUtils.getFontMaximumHeight(mPaintAxisLabel) + 30f;
    mMainRectF.bottom = getHeight() - getPaddingBottom() - PaintUtils.getFontMaximumHeight(mPaintScalesLabel) - 30f;
    if (Float.isNaN(mAnchorY)) {
      mAnchorY = mMainRectF.bottom - 0.5f * mGridsBasicY;
    }
    // 网格区域
    mDrawRectF.left = mMainRectF.left;
    mDrawRectF.top = mMainRectF.top + 25f;
    mDrawRectF.right = mMainRectF.right - 25f;
    mDrawRectF.bottom = mMainRectF.bottom;
  }

  @Override
  protected void onThreadDraw(Canvas canvas) {
    measureLeftAreaWidth();
    drawAxisX(canvas);
    drawAxisY(canvas);
    drawGridsX(canvas);
    drawGridsY(canvas);
    //drawMapping(canvas)  ;
  }

  private void measureLeftAreaWidth() {
    // 计算最小X值，随界面滑动，这个值可能是不断变化的（Y轴刻度标签的宽度会变化）
    final int times = (int) Math.ceil((mAnchorY - mMainRectF.bottom) / mGridsBasicY);
    final int index = mAxisScalesY.index + times;
    final int count = (int) Math.ceil(getHeight() / mGridsBasicY + 1);
    final int leftMaxWidth = mAxisScalesY.getMaximumWidth(mPaintScalesLabel, index, index + count);
    mMainRectF.left = getPaddingLeft() + leftMaxWidth + 30f;
    mDrawRectF.left = mMainRectF.left;
  }

  /**
   * 绘制X坐标轴
   */
  private void drawAxisX(Canvas canvas) {
    // X轴线
    canvas.drawLine(mMainRectF.left, mMainRectF.bottom, mMainRectF.right, mMainRectF.bottom, mPaintAxis);
    // X轴箭头
    canvas.drawLine(mMainRectF.right, mMainRectF.bottom, mMainRectF.right - 15f, mMainRectF.bottom + 10f, mPaintAxis);
    canvas.drawLine(mMainRectF.right, mMainRectF.bottom, mMainRectF.right - 15f, mMainRectF.bottom - 10f, mPaintAxis);
    // X标签
    final float textX = mMainRectF.right + 15f;
    final float textY = mMainRectF.bottom + 0.5f * PaintUtils.getTextBoundsHeight(mPaintAxisLabel, mAxisLabelX);
    canvas.drawText(mAxisLabelX, textX, textY, mPaintAxisLabel);
  }

  /**
   * 绘制Y坐标轴
   */
  private void drawAxisY(Canvas canvas) {
    // Y轴线
    canvas.drawLine(mMainRectF.left, mMainRectF.bottom, mMainRectF.left, mMainRectF.top, mPaintAxis);
    // Y轴箭头
    canvas.drawLine(mMainRectF.left, mMainRectF.top, mMainRectF.left - 10f, mMainRectF.top + 15f, mPaintAxis);
    canvas.drawLine(mMainRectF.left, mMainRectF.top, mMainRectF.left + 10f, mMainRectF.top + 15f, mPaintAxis);
    // Y标签
    final float textX = mMainRectF.left - 0.5f * PaintUtils.getTextBoundsWidth(mPaintAxisLabel, mAxisLabelY);
    final float textY = mMainRectF.top - 15f;
    canvas.drawText(mAxisLabelY, textX, textY, mPaintAxisLabel);
  }

  /**
   * 绘制X轴刻度、竖直网格线和刻度标签
   */
  private void drawGridsX(Canvas canvas) {
    final int times = (int) Math.ceil((mMainRectF.left - mAnchorX) / mGridsBasicX);
    int index = mAxisScalesX.index + times;
    float currentX = mAnchorX + times * mGridsBasicX;
    final int count = (int) Math.ceil((mMainRectF.right - 50f - currentX) / mGridsBasicX);
    final int width = mAxisScalesX.getMaximumWidth(mPaintScalesLabel, index, index + count);
    final int interval = Math.max(1, (int) Math.ceil(2 * width / mGridsBasicX));
    int tag = index % interval;
    while (currentX <= mMainRectF.right - 50f) {
      // 竖直网格线
      canvas.drawLine(currentX, mMainRectF.bottom, currentX, mMainRectF.top + 25f, mPaintGrids);
      // X轴刻度
      canvas.drawLine(currentX, mMainRectF.bottom, currentX, mMainRectF.bottom - 15f, mPaintAxis);
      // X轴刻度标签
      if (index >= 0 && index < mAxisScalesX.count) {
        if (tag == 0) {
          final String text = mAxisScalesX.getText(index);
          final float textX = currentX - 0.5f * PaintUtils.getTextBoundsWidth(mPaintScalesLabel, text);
          final float textY = mMainRectF.bottom + PaintUtils.getTextBoundsHeight(mPaintScalesLabel, text) + 15f;
          canvas.drawText(text, textX, textY, mPaintScalesLabel);
        }
        tag = ++tag % interval;
      }
      ++index;
      currentX += mGridsBasicX;
    }
  }

  /**
   * 绘制Y轴刻度、水平网格线和刻度标签
   */
  private void drawGridsY(Canvas canvas) {
    final int times = (int) Math.ceil((mAnchorY - mMainRectF.bottom) / mGridsBasicY);
    int index = mAxisScalesY.index + times;
    float currentY = mAnchorY - times * mGridsBasicY;
    final int height = (int) Math.ceil(mPaintScalesLabel.getFontMetrics().bottom - mPaintScalesLabel.getFontMetrics().top);
    final int interval = Math.max(1, (int) Math.ceil(2 * height / mGridsBasicY));
    int tag = index % interval;
    while (currentY >= mMainRectF.top + 50f) {
      // 水平网格线
      canvas.drawLine(mMainRectF.left, currentY, mMainRectF.right - 25f, currentY, mPaintGrids);
      // Y轴刻度
      canvas.drawLine(mMainRectF.left, currentY, mMainRectF.left + 15f, currentY, mPaintAxis);
      // Y轴刻度标签
      if (index >= 0 && index < mAxisScalesY.count) {
        if (tag == 0) {
          final String text = mAxisScalesY.getText(index);
          final float textX = mMainRectF.left - PaintUtils.getTextBoundsWidth(mPaintScalesLabel, text) - 15f;
          final float textY = currentY + 0.5f * PaintUtils.getTextBoundsHeight(mPaintScalesLabel, text);
          canvas.drawText(text, textX, textY, mPaintScalesLabel);
        }
        tag = ++tag % interval;
      }
      ++index;
      currentY -= mGridsBasicY;
    }
  }

  /**
   * 设置坐标轴颜色
   *
   * @param color 颜色 argb
   */
  public void setAxisColor(@ColorInt int color) {
    if (mAxisColor != color) {
      mAxisColor = color;
      configPaint(PaintType.AXIS);
      invalidate();
    }
  }

  /**
   * 设置坐标轴厚度
   *
   * @param thickness 厚度 px
   */
  public void setAxisThickness(@Px int thickness) {
    if (mAxisThickness != thickness) {
      mAxisThickness = thickness;
      configPaint(PaintType.AXIS);
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置网格X轴大小
   *
   * @param sizeX 大小 px
   */
  public void setBasicGridX(@Px int sizeX) {
    if (mGridsBasicX != sizeX) {
      mGridsBasicX = sizeX;
      mGridsBasicKeepX = mGridsBasicX;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置网格Y轴大小
   *
   * @param sizeY px
   */
  public void setBasicGridY(@Px int sizeY) {
    if (mGridsBasicY != sizeY) {
      mGridsBasicY = sizeY;
      mGridsBasicKeepY = mGridsBasicY;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置网格颜色
   *
   * @param color 颜色 argb
   */
  public void setGridsColor(@ColorInt int color) {
    if (mGridsColor != color) {
      mGridsColor = color;
      configPaint(PaintType.GRIDS);
      invalidate();
    }
  }

  /**
   * 设置网格厚度
   *
   * @param thickness 厚度 px
   */
  public void setGridsThickness(@Px int thickness) {
    if (mGridsThickness != thickness) {
      mGridsThickness = thickness;
      configPaint(PaintType.GRIDS);
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置X轴标签文本
   *
   * @param labelX 标签文本
   */
  public void setAxisLabelX(String labelX) {
    if (!TextUtils.equals(mAxisLabelX, labelX)) {
      mAxisLabelX = labelX;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置Y轴标签文本
   *
   * @param labelY 标签文本
   */
  public void setAxisLabelY(String labelY) {
    if (!TextUtils.equals(mAxisLabelY, labelY)) {
      mAxisLabelY = labelY;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置坐标轴标签文本颜色
   *
   * @param color 颜色 argb
   */
  public void setAxisLabelTextColor(@ColorInt int color) {
    if (mAxisLabelTextColor != color) {
      mAxisLabelTextColor = color;
      configPaint(PaintType.AXIS_LABEL);
      invalidate();
    }
  }

  /**
   * 设置坐标轴标签文本字体大小
   *
   * @param textSize 字体大小 px
   */
  public void setAxisLabelTextSize(@Px int textSize) {
    if (mAxisLabelTextSize != textSize) {
      mAxisLabelTextSize = textSize;
      configPaint(PaintType.AXIS_LABEL);
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置坐标轴标签文本字体
   *
   * @param typeface 文本字体
   */
  public void setAxisLabelTypeface(Typeface typeface) {
    mAxisLabelTypeface = typeface;
    configPaint(PaintType.AXIS_LABEL);
    invalidate();

  }

  /**
   * 设置X轴刻度列表
   *
   * @param scaleList 标签文本
   */
  public void setAxisScalesX(AxisScales scaleList) {
    mAxisScalesX = scaleList;
    requestLayout();
    invalidate();
  }

  /**
   * 设置Y轴刻度列表
   *
   * @param scaleList 标签文本
   */
  public void setAxisScalesY(AxisScales scaleList) {
    mAxisScalesY = scaleList;
    requestLayout();
    invalidate();
  }

  /**
   * 设置刻度列表标签文本颜色
   *
   * @param color 颜色 argb
   */
  public void setAxisScaleLabelTextColor(@ColorInt int color) {
    if (mAxisScalesLabelTextColor != color) {
      mAxisScalesLabelTextColor = color;
      configPaint(PaintType.SCALE_LABEL);
      invalidate();
    }
  }

  /**
   * 设置刻度列表标签文本字体大小
   *
   * @param textSize 字体大小 px
   */
  public void setAxisScaleLabelTextSize(@Px int textSize) {
    if (mAxisScalesLabelTextSize != textSize) {
      mAxisScalesLabelTextSize = textSize;
      configPaint(PaintType.SCALE_LABEL);
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置刻度列表标签文本字体
   *
   * @param typeface 文本字体
   */
  public void setAxisScaleLabelTypeface(Typeface typeface) {
    mAxisScalesLabelTypeface = typeface;
    configPaint(PaintType.SCALE_LABEL);
    invalidate();
  }

  /**
   * 重置网格大小
   */
  public void resetGridSize() {
    mGridsBasicX = mGridsBasicKeepX;
    mGridsBasicY = mGridsBasicKeepY;
    requestLayout();
    invalidate();
  }

  /**
   * 重置锚点
   */
  public void resetAnchorPoint() {
    mAnchorX = mMainRectF.left + 0.5f * mGridsBasicX;
    mAnchorY = mMainRectF.bottom - 0.5f * mGridsBasicY;
    invalidate();
  }

  /**
   * AXIS 坐标轴画笔
   * GRIDS 坐标网格画笔
   * AXIS_LABEL 坐标轴标签画笔
   * SCALE_LABEL 坐标轴刻度标签画笔
   */
  protected enum PaintType {AXIS, GRIDS, AXIS_LABEL, SCALE_LABEL}
}